#ifndef COCKPITBAR_H
#define COCKPITBAR_H

#include <QtGui/QBrush>
#include <QtGui/QFont>
#include <QtGui/QPainter>
#include <QtGui/QPaintEvent>
#include <QtGui/QPen>
#include <QtWidgets/QWidget>

#include <cmath>

namespace CockpitBarUtils
{
    template <typename Float>
    Float modAbs180(Float value);

    template <typename Float>
    Float mod0Plus360(Float value);

    QFont fitTextToRect(const QString & text
                                , QFont font
                                , const QRect & rect
                                );

    QFont fitTextToRectF(const QString & text
                                , QFont font
                                , const QRectF & rect
                                );
}

template<typename Value>
class CockpitBar : public QWidget
{
public:
    using RestrictionPolicy = std::function<Value(const Value &)>;

    static const RestrictionPolicy NO_RESTRICTION;

    CockpitBar(const Value & value, RestrictionPolicy restriction_policy = NO_RESTRICTION)
        : QWidget()
        , _restriction_policy(restriction_policy)
    {
        setValue(value);
    }

    const Value & value() const
    {
        return _value;
    }

    void setValue(const Value & value)
    {
        _value = _restriction_policy(value);
    }

protected:
    QPointF center()
    {
        return { 0.5 * this->width(), 0.5 * this->height() };
    }

    QRectF boundingRect() const
    {
        return {0, 0, qreal(width()), qreal(height())};
    }

    void paintEvent(QPaintEvent * /*event*/) override
    {
        QBrush dark_green_brush(Qt::darkGreen);
        QPen black_pen(Qt::black);
        black_pen.setWidth(2);

        QPainter painter(this);

        painter.setPen(black_pen);
        painter.fillRect(boundingRect(), dark_green_brush);
        painter.drawRect(boundingRect());
    }

    void keyPressEvent(QKeyEvent * event) override final
    {
        event->ignore();
    }

    void keyReleaseEvent(QKeyEvent * event) override final
    {
        event->ignore();
    }

    const RestrictionPolicy & restrictionPolicy()
    {
        return _restriction_policy;
    }

private:
    Value _value;
    RestrictionPolicy _restriction_policy;
};

namespace CockpitBarUtils {
    template <typename Float>
    Float modAbs180(Float value)
    {
        int int_value = (value > 0) ? std::floor(value) : std::ceil(value);
        Float shift = value - int_value;
        Float clamped = (int_value % 360) + shift;
        if (std::abs(clamped) > 180)
        {
            clamped += (clamped > 0) ? -360 : 360;
        }
        return clamped;
    }

    template <typename Float>
    Float mod0Plus360(Float value)
    {
        int int_value = (value > 0) ? std::floor(value) : std::ceil(value);
        Float shift = value - int_value;
        Float clamped = (int_value % 360) + shift;
        if (clamped < 0)
        {
            clamped += 360;
        } else if (clamped > 360)
        {
            clamped -= 360;
        }
        return clamped;
    }
}

template <typename Value>
const typename CockpitBar<Value>::RestrictionPolicy CockpitBar<Value>::NO_RESTRICTION =
    [](const Value & value) -> Value { return value; };

#endif // COCKPITBAR_H
